﻿using System.Security;
using Honeycomb.Protocol;
using Honeycomb.Transport.Ipv4Synchronous;
using System;

namespace Honeycomb.Core.Client
{
    /// <summary>
    /// Responsible for communication with the server.
    /// </summary>
    public sealed class GridClient : IDisposable
    {
        private readonly ProtocolClient protocolClient;

        /// <summary>
        /// Constructor, connects and authenticates with the specified URI.
        /// </summary>
        /// <param name="uri"></param>
        public GridClient(GridUri uri)
        {
            if (uri == null)
                throw new ArgumentNullException("uri");

            // Connect.
            protocolClient = new ProtocolClient(new NetworkClient(uri.Host, uri.Port));

            // Authenticate request.
            protocolClient.SendAuthenticateRequest(uri.Username, uri.Password);
            bool authenticated = protocolClient.ReadAuthenticateResponse();

            // Determine if we are authenticated.
            if (!authenticated)
                throw new SecurityException("Invalid username and/or password.");
        }

        /// <summary>
        /// Request a task from the server.
        /// </summary>
        /// <returns>Serialized task.</returns>
        public byte[] RequestTask()
        {
            protocolClient.SendTaskRequest();
            return protocolClient.ReadTaskResponse();
        }

        /// <summary>
        /// Request an assembly from the server.
        /// </summary>
        /// <param name="assemblyName">Assembly name.</param>
        /// <returns>Serialized assembly.</returns>
        public byte[] RequestAssembly(string assemblyName)
        {
            protocolClient.SendAssemblyRequest(assemblyName);
            return protocolClient.ReadAssemblyResponse();
        }

        /// <summary>
        /// Send task execution result to server.
        /// </summary>
        /// <param name="result">Task execution result to send.</param>
        public void SendResult(TaskExecutionResult result)
        {
            if (result == null)
                throw new ArgumentNullException("result");

            protocolClient.SendResultRequest(result.Task, result.Result, result.Exception);
            protocolClient.ReadResultResponse();
        }

        /// <summary>
        /// Dispose.
        /// </summary>
        public void Dispose()
        {
            protocolClient.Dispose();
        }
    }
}
